package org.shiro.realm;

import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.ByteSource;
import org.shiro.entity.Permission;
import org.shiro.entity.Role;
import org.shiro.entity.User;
import org.shiro.matcher.JwtCredentialsMatcher;
import org.shiro.serialize.ShiroByteSource;
import org.shiro.service.PermissionService;
import org.shiro.service.RoleService;
import org.shiro.service.UserService;
import org.shiro.util.PwdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/** @author LENOVO */
@Slf4j
@Service
public class ShiroRealm extends AuthorizingRealm {
  @Autowired private UserService userService;
  @Autowired private RoleService roleService;
  @Autowired private PermissionService permissionService;

  /**
   * 授权
   *
   * @param principals
   * @return
   */
  @Override
  protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    Subject subject = SecurityUtils.getSubject();
    String username = (String) subject.getPrincipal();
    User user = userService.findUserByName(username);
    List<String> perms = new ArrayList<>();
    List<String> roles = new ArrayList<>();
    //    根据查找出用户的Id查找角色
    List<Role> roleList = roleService.selectByUserId(user.getId());
    if (roleList != null && roleList.size() > 0) {
      for (Role role : roleList) {
        roles.add(role.getRolename());
        //       根据查找出角色的Id查找权限
        List<Permission> menus = permissionService.queryMenuByRoleId(role.getId());
        if (menus != null && menus.size() > 0) {
          for (Permission menu : menus) {
            perms.add(menu.getPerms());
          }
        }
      }
    }
    SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    // 将角色放入shiro中
    info.addRoles(roles);
    // 将权限放入shiro中
    info.addStringPermissions(perms);
    return info;
  }
  /**
   * 认证/登录
   *
   * @param authenticationToken
   * @return
   * @throws AuthenticationException
   */
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
      throws AuthenticationException {
    if (authenticationToken.getPrincipal() == null) {
      return null;
    }
    UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
    String username = token.getUsername();
    String password = String.valueOf(token.getPassword());
    User user = userService.findUserByName(username);
    if (user == null) {
      throw new UnknownAccountException("未找到当前用户");
    }
    if (!user.getPassword().equals(PwdUtils.encryptPassword(password, user.getSalt()))) {
      throw new IncorrectCredentialsException("输入口令与原始口令不一致");
    }
    if (user.getStatus().equals(0)) {
      throw new LockedAccountException("当前用户已被禁用");
    }
    SimpleAuthenticationInfo info =
        new SimpleAuthenticationInfo(
            user.getUsername(), user.getPassword(), new ShiroByteSource(user.getSalt()), getName());
    return info;
  }

  //  @Override
  //  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken auth)
  //      throws AuthenticationException {
  //    String token = auth.getCredentials().toString();
  //    String username = JWTUtil.getUsername(token);
  //    if (username == null) {
  //      throw new AuthenticationException("令牌无效");
  //    }
  //    User user = (User) redisUtils.get(token);
  //    if (user == null) {
  //      throw new AuthenticationException("令牌已过期");
  //    } else {
  //      redisUtils.expire(token, 2);
  //      return new SimpleAuthenticationInfo(token, token, "ShiroRealm");
  //    }
  //  }

  /** 大坑！，必须重写此方法，不然Shiro会报错
   * 判断AuthenticationToken 参数是不是 JWTToken类型如果是才进入*/
  //  @Override
  //  public boolean supports(AuthenticationToken token) {
  //    return token instanceof JwtToken;
  //  }

//  public ShiroRealm(){
//    // JWT方法才是真正验证token的地方
//    this.setCredentialsMatcher(new JwtCredentialsMatcher());
//  }
}
